14. Code Checkpoint: Testing Global App Navigation
L5 P4 A12 Testing Global App Navigation V2
In this step, you'll test app level navigation, including:
- The navigation drawer
- The app toolbar
- The Up button
- The Back button
Step 1: Create AppNavigationTest
- Create a file and class called AppNavigationTest.kt in
androidTest:
Set up your test similarly to how you set up TasksActivityTest.
- Add the appropriate annotations for a class that uses AndroidX Test libraries and is an end-to-end test.
- Set up your
taskRepository. - Register and unregister the correct idling resources.
When done, AppNavigationTest should look like this:
AppNavigationTest.kt
@RunWith(AndroidJUnit4::class)
@LargeTest
class AppNavigationTest {
private lateinit var tasksRepository: TasksRepository
// An Idling Resource that waits for Data Binding to have no pending bindings.
private val dataBindingIdlingResource = DataBindingIdlingResource()
@Before
fun init() {
tasksRepository = ServiceLocator.provideTasksRepository(getApplicationContext())
}
@After
fun reset() {
ServiceLocator.resetRepository()
}
/**
* Idling resources tell Espresso that the app is idle or busy. This is needed when operations
* are not scheduled in the main Looper (for example when executed on a different thread).
*/
@Before
fun registerIdlingResource() {
IdlingRegistry.getInstance().register(EspressoIdlingResource.countingIdlingResource)
IdlingRegistry.getInstance().register(dataBindingIdlingResource)
}
/**
* Unregister your idling resource so it can be garbage collected and does not leak any memory.
*/
@After
fun unregisterIdlingResource() {
IdlingRegistry.getInstance().unregister(EspressoIdlingResource.countingIdlingResource)
IdlingRegistry.getInstance().unregister(dataBindingIdlingResource)
}
}
Step 2: Set up your Navigation tests
The starter code below outlines three tests and describes what they should do. Each test is setup so that it:
- Configures the repository for the test.
- Creates an
ActivityScenario. - Properly sets up your
DataBindingIdingResource.
Add the code now.
- Copy this code into the
AppNavigationTestclass:
AppNavigationTest.kt
@Test
fun tasksScreen_clickOnDrawerIcon_OpensNavigation() {
// Start the Tasks screen.
val activityScenario = ActivityScenario.launch(TasksActivity::class.java)
dataBindingIdlingResource.monitorActivity(activityScenario)
// 1. Check that left drawer is closed at startup.
// 2. Open drawer by clicking drawer icon.
// 3. Check if drawer is open.
// When using ActivityScenario.launch(), always call close()
activityScenario.close()
}
@Test
fun taskDetailScreen_doubleUpButton() = runBlocking {
val task = Task("Up button", "Description")
tasksRepository.saveTask(task)
// Start the Tasks screen.
val activityScenario = ActivityScenario.launch(TasksActivity::class.java)
dataBindingIdlingResource.monitorActivity(activityScenario)
// 1. Click on the task on the list.
// 2. Click on the edit task button.
// 3. Confirm that if we click Up button once, we end up back at the task details page.
// 4. Confirm that if we click Up button a second time, we end up back at the home screen.
// When using ActivityScenario.launch(), always call close().
activityScenario.close().
}
@Test
fun taskDetailScreen_doubleBackButton() = runBlocking {
val task = Task("Back button", "Description")
tasksRepository.saveTask(task)
// Start Tasks screen.
val activityScenario = ActivityScenario.launch(TasksActivity::class.java)
dataBindingIdlingResource.monitorActivity(activityScenario)
// 1. Click on the task on the list.
// 2. Click on the Edit task button.
// 3. Confirm that if we click Back once, we end up back at the task details page.
// 4. Confirm that if we click Back a second time, we end up back at the home screen.
// When using ActivityScenario.launch(), always call close()
activityScenario.close().
}
Step 3: Write your Navigation Tests
- Copy the
getToolbarNavigationContentDescriptionextension function and add it to the end of AppNavigationTest.kt (outside of the class):
AppNavigationTest.kt
fun <T : Activity> ActivityScenario<T>.getToolbarNavigationContentDescription()
: String {
var description = ""
onActivity {
description =
it.findViewById<Toolbar>(R.id.toolbar).navigationContentDescription as String
}
return description
}
The snippets of code below should help you complete the tests.
Here's an example of using the getToolbarNavigationContentDescription extension function to click on the navigation button:
Clicking the toolbar navigation button
onView(
withContentDescription(
activityScenario
.getToolbarNavigationContentDescription()
)
).perform(click())
This code checks whether the navigation drawer itself is either open or closed:
Checking that the navigation drawer is open
onView(withId(R.id.drawer_layout))
.check(matches(isOpen(Gravity.START))) // Left drawer is open.
onView(withId(R.id.drawer_layout))
.check(matches(isClosed(Gravity.START))) // Left Drawer is closed.
And here's an example of clicking the system back button:
Clicking the system Back button
pressBack()
// You'll need to import androidx.test.espresso.Espresso.pressBack.
- Using the examples above and your knowledge of Espresso, finish
tasksScreen_clickOnAndroidHomeIcon_OpensNavigation,taskDetailScreen_doubleUpButton(), andtaskDetailScreen_doubleBackButton. - Run your tests, and confirm everything works!
The completed test is in the end_codelab_3 branch of the repository here, so that you can compare.
Optional Step: Download the Final Code (Code Checkpoint)
This was the final code step! At this point, if you'd like, you can download the final code here, download a zip of the final code here, OR you can clone the Github repository for the code:
$ git clone https://github.com/udacity/android-testing.git
$ cd android-architecture
$ git checkout end_codelab_3